/*
 * FaceCat图形通讯框架(非开源)
 * 著作权编号:2015SR229355+2020SR0266727
 * 上海卷卷猫信息技术有限公司
 */

#include "stdafx.h"
#include "FCView.h"
#include "FCNative.h"

namespace FaceCat{
    FCView* FCNative::findView(const FCPoint& mp, ArrayList<FCView*> *views){
        int size = (int)views->size();
        for(int i = size - 1; i >= 0; i--){
            FCView *view = views->get(i);
            if(view->isVisible()){
                bool hasPoint = view->containsPoint(mp);
                if (hasPoint)
                {
                    ArrayList<FCView*> subViews;
                    getSortedViews(view, &subViews);
                    FCView *subView = findView(mp, &subViews);
                    subViews.clear();
                    if (subView)
                    {
                        return subView;
                    }
                    return view;
                }
            }
        }
        return 0;
    }
    
    FCView* FCNative::findView(const String& name, ArrayList<FCView*> *views){
        for(int c = 0; c < views->size(); c++){
            FCView *view = views->get(c);
            if(view->getName() == name){
                return view;
            }
            else{
                ArrayList<FCView*> subViews = view->m_views;
                if(subViews.size() > 0){
                    FCView *fView = findView(name, &subViews);
                    if(fView){
                        return fView;
                    }
                }
            }
        }
        return 0;
    }
    
    FCView* FCNative::findPreviewsView(FCView *view){
        if(view->allowPreviewsEvent()){
            return view;
        }
        else{
            FCView *parent = view->getParent();
            if(parent){
                return findPreviewsView(parent);
            }
            else{
                return view;
            }
        }
    }
    
    FCView* FCNative::findWindow(FCView *view){
        if(view->isWindow()){
            return view;
        }
        else{
            FCView *parent = view->getParent();
            if(parent){
                return findWindow(parent);
            }
            else{
                return view;
            }
        }
    }
    
    float FCNative::getPaintingOpacity(FCView *view){
        float opacity = view->getOpacity();
        FCView *parent = view->getParent();
        if (parent){
            opacity *= getPaintingOpacity(parent);
        }
        else{
            opacity *= m_opacity;
        }
        return opacity;
    }
    
    bool FCNative::getSortedViews(FCView *parent, ArrayList<FCView*> *sortedViews){
        ArrayList<FCView*> views;
        if (parent){
            views = parent->m_views;
        }
        else{
            views = m_views;
        }
        int viewSize = views.size();
        int index = 0;
        for (int i = 0; i < viewSize; i++) {
            FCView *view = views.get(i);
            if (view->isVisible()) {
                if (view->isTopMost()) {
                    sortedViews->add(view);
                }
                else {
                    sortedViews->insert(index, view);
                    index++;
                }
            }
        }
        return sortedViews->size() > 0;
    }
    
    
    void FCNative::getTabStopViews(FCView *view, ArrayList<FCView*> *tabStopViews){
        ArrayList<FCView*> views = view->m_views;
        for(int c = 0; c < views.size(); c++){
            FCView *subView = views.get(c);
            if (!subView->isWindow()){
                if (subView->isEnabled() && subView->isTabStop()){
                    tabStopViews->add(subView);
                }
                getTabStopViews(subView, tabStopViews);
            }
        }
    }
    
    bool FCNative::isPaintEnabled(FCView *view){
        if (view->isEnabled()){
            FCView *parent = view->getParent();
            if (parent){
                return isPaintEnabled(parent);
            }
            else{
                return true;
            }
        }
        else{
            return false;
        }
    }

    void FCNative::renderView(const FCRect& rect, FCView *view, float opacity){
        FCRect destRect;
        FCPoint cPoint = clientPoint(view);
        int clx = cPoint.x;
        int cly = cPoint.y;
        FCRect bounds = {clx, cly, clx + view->getWidth(), cly + view->getHeight()};
        if (view->useRegion()){
            FCRect clipRect = view->getRegion();
            bounds.left += clipRect.left;
            bounds.top += clipRect.top;
            bounds.right = bounds.left + clipRect.right - clipRect.left;
            bounds.bottom = bounds.top + clipRect.bottom - clipRect.top;
        }
        if (view->isVisible() && m_host->getIntersectRect(&destRect, &rect, &bounds) > 0){
            FCRect clipRect = {destRect.left - clx, destRect.top - cly,
                destRect.right - clx, destRect.bottom - cly};
            float newOpacity = view->getOpacity() * opacity;
            setPaint(clx, cly, clipRect, newOpacity);
            FCSize oldSize = view->getSize();
            bool flag = view->onPrePaint(m_paint, clipRect);
            FCSize newSize = view->getSize();
            if(oldSize.cx != newSize.cx || oldSize.cy != newSize.cy){
                bounds.left  = clx;
                bounds.top = cly;
                bounds.right = clx + view->getWidth();
                bounds.bottom = cly + view->getHeight();
                if (view->useRegion()){
                    FCRect clipRect2 = view->getRegion();
                    bounds.left += clipRect2.left;
                    bounds.top += clipRect2.top;
                    bounds.right = bounds.left + clipRect2.right - clipRect2.left;
                    bounds.bottom = bounds.top + clipRect2.bottom - clipRect2.top;
                }
                if(m_host->getIntersectRect(&destRect, &rect, &bounds) > 0){
                    clipRect.left = destRect.left - clx;
                    clipRect.top = destRect.top - cly;
                    clipRect.right = destRect.right - clx;
                    clipRect.bottom = destRect.bottom - cly;
                    setPaint(clx, cly, clipRect, newOpacity);

                }else{
                    flag = false;
                    return;
                }
            }
            if(!flag){
                view->onPaint(m_paint, clipRect);
            }
            
            ArrayList<FCView*> views = view->m_views;
            int viewSize = views.size();
            ArrayList<FCView*> topViews;
            for (int i = 0; i < viewSize; i++)
            {
                FCView *subView = views.get(i);
                if (subView->isVisible())
                {
                    if (subView->isTopMost())
                    {
                        topViews.add(subView);
                        //sortedViews.add(view);
                    }
                    else
                    {
                        renderView(destRect, subView, newOpacity);
                    }
                }
            }
            int topViewsSize = topViews.size();
            for (int i = 0; i < topViewsSize; i++)
            {
                renderView(destRect, topViews.get(i), newOpacity);
            }
            topViews.clear();
            setPaint(clx, cly, clipRect, newOpacity);
            if(!flag){
                view->onPaintBorder(m_paint, clipRect);
            }
        }
    }
    
    void FCNative::renderViews(const FCRect& rect, ArrayList<FCView*> *views, float opacity){
        m_paint->setResourcePath(m_resourcePath);
        for(int c = 0; c < views->size(); c++){
            FCView *view = views->get(c);
            renderView(rect, view, opacity);
        }
    }
    
    void FCNative::setCursor(FCView *view){
        FCCursors cursor = view->getCursor();
        if(!isPaintEnabled(view)){
            cursor = FCCursors_Arrow;
        }
        if(cursor != getCursor()){
            setCursor(cursor);
        }
    }
    
    void FCNative::setPaint(int offsetX, int offsetY, const FCRect& clipRect, float opacity){
        FCPoint offset ={offsetX, offsetY};
        m_paint->setOffset(offset);
        m_paint->setClip(clipRect);
        m_paint->setOpacity(opacity);
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    FCNative::FCNative(){
        m_allowScaleSize = false;
        m_size.cx = 0;
        m_size.cy = 0;
        m_drawBeginPoint.x = 0;
        m_drawBeginPoint.y = 0;
        m_dragBeginRect.left = 0;
        m_dragBeginRect.top = 0;
        m_dragBeginRect.right = 0;
        m_dragBeginRect.bottom = 0;
        m_draggingView = 0;
        m_dragStartOffset.x = 0;
        m_dragStartOffset.y = 0;
        m_focusedView = 0;
        m_host = 0;
        m_touchDownView = 0;
        m_touchDownPoint.x = 0;
        m_touchDownPoint.y = 0;
        m_touchMoveView = 0;
        m_opacity = 1;
        m_paint = 0;
        m_rotateAngle = 0;
        m_scaleSize.cx = 0;
        m_scaleSize.cy = 0;
        m_lockUpdate = false;
    }
    
    FCNative::~FCNative(){
        m_draggingView = 0;
        m_focusedView = 0;
        m_touchDownView = 0;
        m_touchMoveView = 0;
        for(int i = 0; i < m_timers.size(); i++){
            stopTimer(m_timers.getKey(i));
        }
        m_timers.clear();
        clearViews();
        if(m_host){
            delete m_host;
            m_host = 0;
        }
        if(m_paint){
            delete m_paint;
            m_paint = 0;
        }
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    bool FCNative::allowScaleSize(){
        return m_allowScaleSize;
    }
    
    void FCNative::setAllowScaleSize(bool value){
        m_allowScaleSize = value;
    }
    
    FCCursors FCNative::getCursor(){
        if(m_host){
            return m_host->getCursor();
        }
        return FCCursors_Arrow;
    }
    
    void FCNative::setCursor(FCCursors value){
        if(m_host){
            m_host->setCursor(value);
        }
    }
    
    FCView* FCNative::getFocusedView(){
        return m_focusedView;
    }
    
    void FCNative::setFocusedView(FCView *value){
        if (m_focusedView != value){
            if (m_focusedView){
                FCView *fView = m_focusedView;
                m_focusedView = 0;
                fView->onLostFocus();
            }
            m_focusedView = value;
            if (m_focusedView){
                m_focusedView->onGotFocus();
            }
        }
    }
    
    FCHost* FCNative::getHost(){
        return m_host;
    }
    
    void FCNative::setHost(FCHost *value){
        if(m_host){
            delete m_host;
        }
        m_host = value;
    }
    
    FCView* FCNative::getHoveredView(){
        return m_touchMoveView;
    }
    
    FCPoint FCNative::getTouchPoint(){
        FCPoint mp ={0};
        if(m_host){
            mp = m_host->getTouchPoint();
        }
        return mp;
    }
    
    float FCNative::getOpacity(){
        return m_opacity;
    }
    
    void FCNative::setOpacity(float value){
        m_opacity = value;
    }
    
    FCPaint* FCNative::getPaint(){
        return m_paint;
    }
    
    void FCNative::setPaint(FCPaint *value){
        if(m_paint){
            delete m_paint;
        }
        m_paint = value;
    }
    
    FCView* FCNative::getPushedView(){
        return m_touchDownView;
    }
    
    String FCNative::getResourcePath(){
        return m_resourcePath;
    }
    
    void FCNative::setResourcePath(const String& value){
        m_resourcePath = value;
    }
    
    int FCNative::getRotateAngle(){
        return m_rotateAngle;
    }
    
    void FCNative::setRotateAngle(int value){
        m_rotateAngle = value;
    }
    
    FCSize FCNative::getScaleSize(){
        return m_scaleSize;
    }
    
    void FCNative::setScaleSize(FCSize value){
        m_scaleSize = value;
    }

    FCSize FCNative::getSize(){
        return m_size;
    }

    void FCNative::setSize(FCSize value){
        m_size = value;
    }
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    void FCNative::addView(FCView *view){
        view->setNative(this);
        m_views.add(view);
        view->onAdd();
    }
    
    void FCNative::bringToFront(FCView *view){
        ArrayList<FCView*> views;
        FCView *parent = view->getParent();
        if(parent){
            parent->bringChildToFront(view);
        }
        else{
            if(m_views.size() > 0){
                for(int c = 0; c < m_views.size(); c++){
                    if(m_views.get(c) == view){
                        m_views.removeAt(c);
                        break;
                    }
                }
                m_views.add(view);
            }
        }
    }
    
    void FCNative::cancelDragging(){
        if(m_draggingView){
            m_draggingView->setBounds(m_dragBeginRect);
            FCView *draggingView = m_draggingView;
            m_draggingView = 0;
            draggingView->onDragEnd();
            FCView *parent = draggingView->getParent();
            if (parent){
                parent->invalidate();
            }
            else{
                invalidate();
            }
        }
    }
    
    void FCNative::clearViews(){
        while((int)m_views.size() > 0){
            FCView *view = m_views.get(0);
            m_views.removeAt(0);
            view->onRemove();
            delete view;
        }
        m_touchDownView = 0;
        m_touchMoveView = 0;
    }

    void FCNative::clearViewState(FCView *view){
        if(view == m_draggingView){
            m_draggingView = 0;
        }
        if(view == m_focusedView){
            m_focusedView = 0;
        }
        if(view == m_touchDownView){
            m_touchDownView = 0;
        }
        if(view == m_touchMoveView){
            m_touchMoveView = 0;
        }
        ArrayList<int> removeTimers;
        for(int i = 0; i < m_timers.size(); i++){
            if(m_timers.getValue(i) == view){
                removeTimers.add(m_timers.getKey(i));
            }
        }
        for(int i = 0; i < removeTimers.size(); i++){
            stopTimer(removeTimers.get(i));
        }
        for(int i = 0; i < view->m_views.size(); i++){
            clearViewState(view->m_views.get(i));
        }
    }
    
    int FCNative::clientX(FCView *view){
        if (view){
            FCView *parent = view->getParent();
            int cLeft = view->getLeft();
            if (parent){
                return cLeft - (view->displayOffset() ? parent->getDisplayOffset().x : 0) +  clientX(parent);
            }
            else{
                return cLeft;
            }
        }
        else{
            return 0;
        }
    }
    
    int FCNative::clientY(FCView *view){
        if (view){
            FCView *parent = view->getParent();
            int cTop = view->getTop();
            if (parent){
                return cTop - (view->displayOffset() ? parent->getDisplayOffset().y : 0) + clientY(parent);
            }
            else{
                return cTop;
            }
        }
        else{
            return 0;
        }
    }

    FCPoint FCNative::clientPoint(FCView *view){
        if (view)
        {
            FCView *parent = view->getParent();
            int cLeft = view->getLeft();
            int cTop = view->getTop();
            if (parent)
            {
                FCPoint parentClientY = clientPoint(parent);
                if (view->displayOffset())
                {
                    FCPoint displayOffset = parent->getDisplayOffset();
                    return {cLeft - displayOffset.x + parentClientY.x,
                        cTop - displayOffset.y + parentClientY.y};
                }
                else
                {
                    return {cLeft + parentClientY.x,
                        cTop + parentClientY.y};
                }
            }
            else
            {
                return {cLeft, cTop};
            }
        }
        else
        {
            return {0, 0};
        }
    }
    
    bool FCNative::containsView(FCView *view){
        if(m_views.size() > 0){
            for(int c = 0; c < m_views.size(); c++){
                if(m_views.get(c) == view){
                    return true;
                }
            }
        }
        return false;
    }
    
    FCView* FCNative::findView(const FCPoint& mp){
        ArrayList<FCView*> subViews;
        if(!getSortedViews(0, &subViews)){
            subViews = m_views;
        }
        return findView(mp, &subViews);
    }
    
    FCView* FCNative::findView(const FCPoint& mp, FCView *parent){
        ArrayList<FCView*> subViews;
        if(!getSortedViews(parent, &subViews)){
            if(parent){
                subViews = parent->m_views;
            }
            else{
                subViews = m_views;
            }
        }
        return findView(mp, &subViews);
    }
    
    FCView* FCNative::findView(const String& name){
        return findView(name, &m_views);
    }
    
    ArrayList<FCView*> FCNative::getViews(){
        return m_views;
    }
    
    void FCNative::insertView(int index, FCView *view){
        view->setNative(this);
        m_views.insert(index, view);
        view->onAdd();
    }
    
    void FCNative::invalidate(){
        if(m_host){
            m_host->invalidate();
        }
    }
    
    void FCNative::invalidate(FCView *view){
        if(m_host){
            int clx = clientX(view);
            int cly = clientY(view);
            FCRect rect ={clx, cly, clx + view->getWidth(), cly + view->getHeight()};
            m_host->invalidate(rect);
        }
    }
    
    bool FCNative::onChar(wchar_t key){
        FCView *focusedView = getFocusedView();
        if(focusedView && isPaintEnabled(focusedView)){
            if(focusedView->isTabStop()){
                FCView *window = findWindow(focusedView);
                if(window){
                    if(!(m_host->isKeyPress(VK_CONTROL)
                         || m_host->isKeyPress(VK_MENU)
                         || m_host->isKeyPress(VK_SHIFT))
                       && key == 9 ){
                        ArrayList<FCView*> tabStopViews;
                        getTabStopViews(window, &tabStopViews);
                        int size = (int)tabStopViews.size();
                        if (size > 0){
                            for (int i = 0; i < size - 1; i++){
                                for (int j = 0; j < size - 1 - i; j++){
                                    FCView *viewLeft = tabStopViews.get(j);
                                    FCView *viewRight = tabStopViews.get(j + 1);
                                    if (viewLeft->getTabIndex() > viewRight->getTabIndex()){
                                        FCView *temp = tabStopViews.get(j + 1);
                                        tabStopViews.set(j + 1, tabStopViews.get(j));
                                        tabStopViews.set(j, temp);
                                    }
                                }
                            }
                            bool change = false;
                            FCView *newFocusedView = 0;
                            for (int i = 0; i < size; i++){
                                FCView *view = tabStopViews.get(i);
                                if (focusedView == view){
                                    if (i < size - 1){
                                        newFocusedView = tabStopViews.get(i + 1);
                                    }
                                    else{
                                        newFocusedView = tabStopViews.get(0);
                                    }
                                    change = true;
                                    break;
                                }
                            }
                            if (!change){
                                newFocusedView = tabStopViews.get(0);
                            }
                            if (newFocusedView != focusedView){
                                newFocusedView->setFocused(true);
                                focusedView = newFocusedView;
                                focusedView->onTabStop();
                                window->invalidate();
                                return true;
                            }
                        }
                    }
                }
            }
            focusedView->onChar(key);
        }
        return false;
    }
    
    void FCNative::onDoubleClick(FCTouchInfo touchInfo){
        FCView *focusedView = getFocusedView();
        if (focusedView && isPaintEnabled(focusedView)){
            FCPoint mp = getTouchPoint();
            int clx = clientX(focusedView);
            int cly = clientY(focusedView);
            FCPoint cmp ={mp.x - clx, mp.y - cly};
            FCTouchInfo newTouchInfo = touchInfo;
            newTouchInfo.m_firstPoint = cmp;
            newTouchInfo.m_secondPoint = cmp;
            focusedView->onDoubleClick(newTouchInfo);
        }
    }
    
    void FCNative::onKeyDown(char key){
        bool handle = onPreviewsKeyEvent(L"onkeydown", key);
        if(handle){
            return;
        }
        FCView *focusedView = getFocusedView();
        if(focusedView && isPaintEnabled(focusedView)){
            focusedView->onKeyDown(key);
        }
    }
    
    void FCNative::onKeyUp(char key){
        FCView *focusedView = getFocusedView();
        if(focusedView && isPaintEnabled(focusedView)){
            focusedView->onKeyUp(key);
        }
    }
    
    void FCNative::onMouseDown(FCTouchInfo touchInfo){
        m_draggingView = 0;
        m_touchDownView = 0;
        FCPoint mp = getTouchPoint();
        m_touchDownPoint = mp;
        ArrayList<FCView*> subViews;
        if(!getSortedViews(0, &subViews)){
            subViews = m_views;
        }
        FCView *view = findView(mp, &subViews);
        if(view){
            FCView *window = findWindow(view);
            if(window && window->isWindow()){
                window->bringToFront();
            }
            if(isPaintEnabled(view)){
                int clx = clientX(view);
                int cly = clientY(view);
                FCPoint cmp ={mp.x - clx, mp.y - cly};
                FCView *focusedView = getFocusedView();
                m_touchDownView = view;
                if (focusedView == getFocusedView()){
                    if(view->canFocus()){
                        setFocusedView(view);
                    }
                }
                FCTouchInfo newTouchInfo = touchInfo;
                newTouchInfo.m_firstPoint = mp;
                newTouchInfo.m_secondPoint = mp;
                if (onPreviewsTouchEvent(L"ontouchdown", m_touchDownView, newTouchInfo)){
                    m_touchDownView = 0;
                    return;
                }
                newTouchInfo.m_firstPoint = cmp;
                newTouchInfo.m_secondPoint = cmp;
                if(m_touchDownView){
                    m_touchDownView->onTouchDown(newTouchInfo);
                }
                if(m_touchDownView){
                    m_touchDownView->onDragReady(&m_dragStartOffset);
                }
            }
        }
    }
    
    void FCNative::onMouseLeave(FCTouchInfo touchInfo){
        if (m_touchMoveView && isPaintEnabled(m_touchMoveView)){
            FCPoint mp = getTouchPoint();
            FCPoint cmp ={mp.x - clientX(m_touchMoveView), mp.y - clientY(m_touchMoveView)};
            FCView *touchMoveView = m_touchMoveView;
            m_touchMoveView = 0;
            FCTouchInfo newTouchInfo = touchInfo;
            newTouchInfo.m_firstPoint = mp;
            newTouchInfo.m_secondPoint = mp;
            if (onPreviewsTouchEvent(L"ontouchleave", m_touchDownView, touchInfo)){
                return;
            }
            newTouchInfo.m_firstPoint = cmp;
            newTouchInfo.m_secondPoint = cmp;
            touchMoveView->onTouchLeave(newTouchInfo);
        }
    }
    
    void FCNative::onMouseMove(FCTouchInfo touchInfo){
        FCPoint mp = getTouchPoint();
        if(m_touchDownView){
            FCTouchInfo newTouchInfo = touchInfo;
            newTouchInfo.m_firstPoint = mp;
            newTouchInfo.m_secondPoint = mp;
            if (onPreviewsTouchEvent(L"ontouchmove", m_touchDownView, newTouchInfo)){
                return;
            }
            FCPoint cmp = {mp.x - clientX(m_touchDownView), mp.y - clientY(m_touchDownView)};
            newTouchInfo.m_firstPoint = cmp;
            newTouchInfo.m_secondPoint = cmp;
            m_touchDownView->onTouchMove(newTouchInfo);
            setCursor(m_touchDownView);
            if (m_touchDownView->allowDrag() && touchInfo.m_firstTouch && touchInfo.m_clicks == 1){
                if (abs(mp.x - m_touchDownPoint.x) > m_dragStartOffset.x
                    || abs(mp.y - m_touchDownPoint.y) > m_dragStartOffset.y){
                    if(m_touchDownView->onDragBegin()){
                        m_dragBeginRect = m_touchDownView->getBounds();
                        m_drawBeginPoint = m_touchDownPoint;
                        m_draggingView = m_touchDownView;
                        m_touchDownView = 0;
                        FCView *parent = m_draggingView->getParent();
                        if (parent){
                            parent->invalidate();
                        }
                        else{
                            invalidate();
                        }
                    }
                }
            }
        }
        else if(m_draggingView){
            FCView *draggingView = m_draggingView;
            int offsetX = mp.x - m_drawBeginPoint.x;
            int offsetY = mp.y - m_drawBeginPoint.y;
            FCRect newBounds = m_dragBeginRect;
            newBounds.left += offsetX;
            newBounds.top += offsetY;
            newBounds.right += offsetX;
            newBounds.bottom += offsetY;
            draggingView->setBounds(newBounds);
            draggingView->onDragging();
            FCView *parent = draggingView->getParent();
            if (parent){
                parent->invalidate();
            }
            else{
                invalidate();
            }
        }
        else{
            ArrayList<FCView*> subViews;
            if(!getSortedViews(0, &subViews)){
                subViews = m_views;
            }
            FCView *view = findView(mp, &subViews);
            if(view){
                FCTouchInfo newTouchInfo = touchInfo;
                newTouchInfo.m_firstPoint = mp;
                newTouchInfo.m_secondPoint = mp;
                if (onPreviewsTouchEvent(L"ontouchmove", view, newTouchInfo)){
                    return;
                }
            }
            if(m_touchMoveView != view){
                if(m_touchMoveView && isPaintEnabled(m_touchMoveView)){
                    if(!m_touchDownView){
                        FCPoint cmp ={mp.x - clientX(m_touchMoveView), mp.y - clientY(m_touchMoveView)};
                        FCView *touchMoveView = m_touchMoveView;
                        m_touchMoveView = 0;
                        FCTouchInfo newTouchInfo = touchInfo;
                        newTouchInfo.m_firstPoint = cmp;
                        newTouchInfo.m_secondPoint = cmp;
                        touchMoveView->onTouchLeave(newTouchInfo);
                    }
                }
                if(view && isPaintEnabled(view)){
                    if(!m_touchDownView){
                        FCPoint cmp ={mp.x - clientX(view), mp.y - clientY(view)};
                        m_touchMoveView = view;
                        FCTouchInfo newTouchInfo = touchInfo;
                        newTouchInfo.m_firstPoint = cmp;
                        newTouchInfo.m_secondPoint = cmp;
                        view->onTouchEnter(newTouchInfo);
                        view->onTouchMove(newTouchInfo);
                        setCursor(view);
                    }
                }
            }
            else{
                if(view && isPaintEnabled(view)){
                    FCPoint cmp ={mp.x - clientX(view), mp.y - clientY(view)};
                    m_touchMoveView = view;
                    FCTouchInfo newTouchInfo = touchInfo;
                    newTouchInfo.m_firstPoint = cmp;
                    newTouchInfo.m_secondPoint = cmp;
                    view->onTouchMove(newTouchInfo);
                    setCursor(view);
                }
            }
        }
    }
    
    void FCNative::onMouseUp(FCTouchInfo touchInfo){
        FCPoint mp = getTouchPoint();
        if(m_touchDownView){
            ArrayList<FCView*> subViews;
            if(!getSortedViews(0, &subViews)){
                subViews = m_views;
            }
            FCView *touchDownView = m_touchDownView;
            if (onPreviewsTouchEvent(L"ontouchup", touchDownView, touchInfo)){
                return;
            }
            if(m_touchDownView){
                FCView *view = findView(mp, &subViews);
                FCPoint cmp = {mp.x - clientX(m_touchDownView), mp.y - clientY(m_touchDownView)};
                FCTouchInfo newTouchInfo = touchInfo;
                newTouchInfo.m_firstPoint = cmp;
                newTouchInfo.m_secondPoint = cmp;
                if(view && view == m_touchDownView){
                    if(touchInfo.m_clicks == 2){
                        m_touchDownView->onDoubleClick(newTouchInfo);
                    }else{
                        m_touchDownView->onClick(newTouchInfo);
                    }
                }
                else{
                    m_touchMoveView = 0;
                }
                if(m_touchDownView){
                    touchDownView = m_touchDownView;
                    m_touchDownView = 0;
                    touchDownView->onTouchUp(newTouchInfo);
                }
            }
        }
        else if (m_draggingView){
            ArrayList<FCView*> subViews;
            if(!getSortedViews(0, &subViews)){
                subViews = m_views;
            }
            FCPoint cmp ={mp.x - clientX(m_touchDownView), mp.y - clientY(m_touchDownView)};
            FCView *draggingView = m_draggingView;
            m_draggingView = 0;
            FCTouchInfo newTouchInfo = touchInfo;
            newTouchInfo.m_firstPoint = mp;
            newTouchInfo.m_secondPoint = mp;
            if (onPreviewsTouchEvent(L"ontouchup", draggingView, newTouchInfo)){
                return;
            }
            newTouchInfo.m_firstPoint = cmp;
            newTouchInfo.m_secondPoint = cmp;
            draggingView->onTouchUp(newTouchInfo);
            draggingView->onDragEnd();
            FCView *parent = draggingView->getParent();
            if (parent){
                parent->invalidate();
            }
            else{
                invalidate();
            }
        }
    }
    
    void FCNative::onMouseWheel(FCTouchInfo touchInfo){
        FCPoint mp = getTouchPoint();
        ArrayList<FCView*> subViews;
        if(!getSortedViews(0, &subViews)){
            subViews = m_views;
        }
        FCView *focusedView = findView(mp, &subViews);
        if(focusedView && isPaintEnabled(focusedView)){
            FCTouchInfo newTouchInfo = touchInfo;
            newTouchInfo.m_firstPoint = mp;
            newTouchInfo.m_secondPoint = mp;
            if (onPreviewsTouchEvent(L"ontouchwheel", focusedView, newTouchInfo)){
                return;
            }
            mp.x -= clientX(focusedView);
            mp.y -= clientY(focusedView);
            newTouchInfo.m_firstPoint = mp;
            newTouchInfo.m_secondPoint = mp;
            focusedView->onTouchWheel(touchInfo);
        }
    }
    
    void FCNative::invalidate(const FCRect& rect){
        if(m_host){
            m_host->invalidate(rect);
        }
    }
    
    void FCNative::onPaint(const FCRect& rect){
        ArrayList<FCView*> subViews;
        if(!getSortedViews(0, &subViews)){
            subViews = m_views;
        }
        renderViews(rect, &subViews, m_opacity);
    }
    
    bool FCNative::onPreviewsKeyEvent(String eventName, char key){
        FCView *focusedView = getFocusedView();
        if(focusedView && isPaintEnabled(focusedView)){
            FCView *window = findWindow(focusedView);
            if(window){
                return window->onPreviewsKeyEvent(eventName, key);
            }
        }
        return false;
    }
    
    bool FCNative::onPreviewsTouchEvent(String eventName, FCView *view, FCTouchInfo touchInfo){
        FCView *previewsView = findPreviewsView(view);
        if (previewsView){
            FCTouchInfo newTouchInfo = touchInfo;
            newTouchInfo.m_firstPoint = previewsView->pointToView(touchInfo.m_firstPoint);
            newTouchInfo.m_secondPoint = previewsView->pointToView(touchInfo.m_secondPoint);
            if (previewsView->onPreviewsTouchEvent(eventName, newTouchInfo)){
                return true;
            }
        }
        return false;
    }
    
    void FCNative::onResize(){
        update();
    }

    void FCNative::onScaling(double scaleFactorX, double scaleFactorY) {
        int viewSize = m_views.size();
        for (int i = 0; i < viewSize; i++) {
            m_views.get(i)->onScaling(scaleFactorX, scaleFactorY);
        }
    }
    
    void FCNative::onTimer(int timerID){
        if(m_timers.containsKey(timerID)){
            m_timers.get(timerID)->onTimer(timerID);
        }
    }
    
    void FCNative::onTouchBegin(FCTouchInfo touchInfo){
        m_draggingView = 0;
        m_touchDownView = 0;
        FCPoint mp = getTouchPoint();
        m_touchDownPoint = mp;
        ArrayList<FCView*> subViews;
        if(!getSortedViews(0, &subViews)){
            subViews = m_views;
        }
        FCView *view = findView(mp, &subViews);
        if(view){
            FCView *window = findWindow(view);
            if(window && window->isWindow()){
                window->bringToFront();
            }
            if(isPaintEnabled(view)){
                FCView *focusedView = getFocusedView();
                m_touchDownView = view;
                if (focusedView == getFocusedView()){
                    if(view->canFocus()){
                        setFocusedView(view);
                    }
                }
                FCTouchInfo newTouchInfo = touchInfo;
                if (onPreviewsTouchEvent(L"ontouchdown", m_touchDownView, newTouchInfo)){
                    m_touchDownView = 0;
                    return;
                }
                newTouchInfo.m_firstPoint = m_touchDownView->pointToView(touchInfo.m_firstPoint);
                newTouchInfo.m_secondPoint = m_touchDownView->pointToView(touchInfo.m_secondPoint);
                if(m_touchDownView){
                    m_touchDownView->onTouchDown(newTouchInfo);
                }
                if(m_touchDownView){
                    m_touchDownView->onDragReady(&m_dragStartOffset);
                }
            }
        }
    }
    
    void FCNative::onTouchCancel(FCTouchInfo touchInfo){
    }
    
    void FCNative::onTouchEnd(FCTouchInfo touchInfo){
        FCPoint mp = getTouchPoint();
        if(m_touchDownView){
            ArrayList<FCView*> subViews;
            if(!getSortedViews(0, &subViews)){
                subViews = m_views;
            }
            FCView *touchDownView = m_touchDownView;
            FCTouchInfo newTouchInfo = touchInfo;
            if (onPreviewsTouchEvent(L"ontouchup", touchDownView, newTouchInfo)){
                return;
            }
            if(m_touchDownView){
                FCView *view = findView(mp, &subViews);
                newTouchInfo.m_firstPoint = m_touchDownView->pointToView(touchInfo.m_firstPoint);
                newTouchInfo.m_secondPoint = m_touchDownView->pointToView(touchInfo.m_secondPoint);
                if(view && view == m_touchDownView){
                    if(touchInfo.m_clicks == 2){
                        m_touchDownView->onDoubleClick(newTouchInfo);
                    }else{
                        m_touchDownView->onClick(newTouchInfo);
                    }
                }
                else{
                    m_touchMoveView = 0;
                }
                if(m_touchDownView){
                    touchDownView = m_touchDownView;
                    m_touchDownView = 0;
                    touchDownView->onTouchUp(newTouchInfo);
                }
            }
        }
        else if (m_draggingView){
            ArrayList<FCView*> subViews;
            if(!getSortedViews(0, &subViews)){
                subViews = m_views;
            }
            FCView *draggingView = m_draggingView;
            m_draggingView = 0;
            FCTouchInfo newTouchInfo = touchInfo;
            if (onPreviewsTouchEvent(L"ontouchup", draggingView, newTouchInfo)){
                return;
            }
            newTouchInfo.m_firstPoint = draggingView->pointToView(touchInfo.m_firstPoint);
            newTouchInfo.m_secondPoint = draggingView->pointToView(touchInfo.m_secondPoint);
            draggingView->onTouchUp(newTouchInfo);
            draggingView->onDragEnd();
            FCView *parent = draggingView->getParent();
            if (parent){
                parent->invalidate();
            }
            else{
                invalidate();
            }
        }
    }
    
    void FCNative::onTouchMove(FCTouchInfo touchInfo){
        FCPoint mp = getTouchPoint();
        if(m_touchDownView){
            FCTouchInfo newTouchInfo = touchInfo;
            if (onPreviewsTouchEvent(L"ontouchmove", m_touchDownView, newTouchInfo)){
                return;
            }
            newTouchInfo.m_firstPoint = m_touchDownView->pointToView(touchInfo.m_firstPoint);
            newTouchInfo.m_secondPoint = m_touchDownView->pointToView(touchInfo.m_secondPoint);
            m_touchDownView->onTouchMove(newTouchInfo);
            setCursor(m_touchDownView);
            if (m_touchDownView->allowDrag()){
                if (abs(mp.x - m_touchDownPoint.x) > m_dragStartOffset.x
                    || abs(mp.y - m_touchDownPoint.y) > m_dragStartOffset.y){
                    if(m_touchDownView->onDragBegin()){
                        m_dragBeginRect = m_touchDownView->getBounds();
                        m_drawBeginPoint = m_touchDownPoint;
                        m_draggingView = m_touchDownView;
                        m_touchDownView = 0;
                        FCView *parent = m_draggingView->getParent();
                        if (parent){
                            parent->invalidate();
                        }
                        else{
                            invalidate();
                        }
                    }
                }
            }
        }
        else if(m_draggingView){
            FCView *draggingView = m_draggingView;
            int offsetX = mp.x - m_drawBeginPoint.x;
            int offsetY = mp.y - m_drawBeginPoint.y;
            FCRect newBounds = m_dragBeginRect;
            newBounds.left += offsetX;
            newBounds.top += offsetY;
            newBounds.right += offsetX;
            newBounds.bottom += offsetY;
            draggingView->setBounds(newBounds);
            draggingView->onDragging();
            FCView *parent = draggingView->getParent();
            if (parent){
                parent->invalidate();
            }
            else{
                invalidate();
            }
        }
    }
    
    void FCNative::removeView(FCView *view){
        clearViewState(view);
        if(view && !view->getParent()){
            for(int c = 0; c < m_views.size(); c++){
                if(m_views.get(c) == view){
                    m_views.removeAt(c);
                    view->onRemove();
                    return;
                }
            }
        }
    }
    
    void FCNative::sendToBack(FCView *view){
        ArrayList<FCView*> views;
        FCView *parent = view->getParent();
        if(parent){
            parent->sendChildToBack(view);
        }
        else{
            if(m_views.size() > 0){
                for(int c = 0; c < m_views.size(); c++){
                    if(m_views.get(c) == view){
                        m_views.removeAt(c);
                        break;
                    }
                }
                m_views.insert(0, view);
            }
        }
    }
    
    void FCNative::setAlign(ArrayList<FCView*> *views){
        int viewSize = (int)views->size();
        for (int i = 0; i < viewSize; i++){
            FCView *view = views->get(i);
            if (view->displayOffset()){
                if (view->getAlign() == FCHorizontalAlign_Left && view->getVerticalAlign() == FCVerticalAlign_Top)
                {
                            continue;
                }
                FCSize parentSize = m_size;
                FCView *parent = view->getParent();
                if (parent){
                    parentSize = parent->getSize();
                }
                FCSize size = view->getSize();
                FCPadding margin = view->getMargin();
                FCPadding padding(0);
                if(parent){
                    padding = parent->getPadding();
                }
                if (view->getAlign() == FCHorizontalAlign_Center){
                    view->setLeft((parentSize.cx - size.cx) / 2);
                }
                else if (view->getAlign() == FCHorizontalAlign_Right){
                    view->setLeft(parentSize.cx - size.cx - margin.right - padding.right);
                }
                if (view->getVerticalAlign() == FCVerticalAlign_Bottom){
                    view->setTop(parentSize.cy - size.cy - margin.bottom - padding.bottom);
                }
                else if (view->getVerticalAlign() == FCVerticalAlign_Middle){
                    view->setTop((parentSize.cy - size.cy) / 2);
                }
            }
        }
    }
    
    void FCNative::setAnchor(ArrayList<FCView*> *views, FCSize oldSize){
        if(oldSize.cx != 0 && oldSize.cy != 0){
            for(int c = 0; c < views->size(); c++){
                FCView *view = views->get(c);
                FCAnchor anchor = view->getAnchor();
                if (anchor.left && anchor.top && !anchor.right && !anchor.bottom)
                {
                    continue;
                }
                FCSize parentSize = m_size;
                FCView *parent = view->getParent();
                if (parent){
                    parentSize = parent->getSize();
                }
                FCRect bounds = view->getBounds();
                if (anchor.right && !anchor.left)
                {
                    bounds.left = bounds.left + parentSize.cx - oldSize.cx;
                }
                if (anchor.bottom && !anchor.top)
                {
                    bounds.top = bounds.top + parentSize.cy - oldSize.cy;
                }
                if (anchor.right)
                {
                    bounds.right = bounds.right + parentSize.cx - oldSize.cx;
                }
                if (anchor.bottom)
                {
                    bounds.bottom = bounds.bottom + parentSize.cy - oldSize.cy;
                }
                view->setBounds(bounds);
            }
        }
    }
    
    void FCNative::setDock(ArrayList<FCView*> *views){
        for(int c = 0; c < views->size(); c++){
            FCView *view = views->get(c);
            FCDockStyle dock = view->getDock();
            if (dock != FCDockStyle_None){
                FCSize parentSize = m_size;
                FCView *parent = view->getParent();
                if (parent){
                    parentSize = parent->getSize();
                }
                FCPadding padding(0);
                if(parent){
                    padding = parent->getPadding();
                }
                FCPadding margin = view->getMargin();
                FCSize cSize = view->getSize();
                FCRect spaceRect = {padding.left + margin.left, padding.top + margin.top, parentSize.cx - padding.right - margin.right, parentSize.cy - padding.bottom - margin.bottom};
                if (dock == FCDockStyle_Bottom)
                {
                    FCRect bounds = {spaceRect.left, spaceRect.bottom - cSize.cy, spaceRect.right, spaceRect.bottom};
                    view->setBounds(bounds);
                }
                else if (dock == FCDockStyle_Fill)
                {
                    FCRect bounds = {spaceRect.left, spaceRect.top, spaceRect.right, spaceRect.bottom};
                    view->setBounds(bounds);
                }
                else if (dock == FCDockStyle_Left)
                {
                    FCRect bounds = {spaceRect.left, spaceRect.top, spaceRect.left + cSize.cx, spaceRect.bottom};
                    view->setBounds(bounds);
                }
                else if (dock == FCDockStyle_Right)
                {
                    FCRect bounds = {spaceRect.right - cSize.cx, spaceRect.top, spaceRect.right, spaceRect.bottom};
                    view->setBounds(bounds);
                }
                else if (dock == FCDockStyle_Top)
                {
                    FCRect bounds = {spaceRect.left, spaceRect.top, spaceRect.right, spaceRect.top + cSize.cy};
                    view->setBounds(bounds);
                }
            }
        }
    }
    
    void FCNative::startTimer(FCView *view, int timerID, int interval){
        m_timers.put(timerID, view);
        if(m_host){
            m_host->startTimer(timerID, interval);
        }
    }
    
    void FCNative::stopTimer(int timerID){
        if(m_timers.containsKey(timerID)){
            if(m_host){
                m_host->stopTimer(timerID);
            }
            m_timers.remove(timerID);
        }
    }
    
    void FCNative::update(){
        if(m_host && !m_lockUpdate){
            FCSize size = m_host->getSize();
            FCSize oldSize = m_size;
            m_size = size;
            if(m_size.cx != 0 && m_size.cy != 0){
                setAlign(&m_views);
                setAnchor(&m_views, oldSize);
                setDock(&m_views);
                int viewsSize = (int)m_views.size();
                for (int i = 0; i < viewsSize; i++){
                    m_views.get(i)->update();
                }
            }
        }
    }

    static int m_changeID = 0;

    void FCNative::addChangeID(){
        m_changeID++;
    }

    int FCNative::getChangeID(){
        return m_changeID;
    }
}
